
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
// 
//   http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
// 
//   http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
import { subPixelOptimize } from '../../util/graphic.js';
import createRenderPlanner from '../helper/createRenderPlanner.js';
import { parsePercent } from '../../util/number.js';
import { map, retrieve2 } from 'zrender/lib/core/util.js';
import { createFloat32Array } from '../../util/vendor.js';
var candlestickLayout = {
	seriesType: 'candlestick',
	plan: createRenderPlanner(),
	reset: function (seriesModel) {
		var coordSys = seriesModel.coordinateSystem;
		var data = seriesModel.getData();
		var candleWidth = calculateCandleWidth(seriesModel, data);
		var cDimIdx = 0;
		var vDimIdx = 1;
		var coordDims = ['x', 'y'];
		var cDimI = data.getDimensionIndex(data.mapDimension(coordDims[cDimIdx]));
		var vDimsI = map(data.mapDimensionsAll(coordDims[vDimIdx]), data.getDimensionIndex, data);
		var openDimI = vDimsI[0];
		var closeDimI = vDimsI[1];
		var lowestDimI = vDimsI[2];
		var highestDimI = vDimsI[3];
		data.setLayout({
			candleWidth: candleWidth,
			// The value is experimented visually.
			isSimpleBox: candleWidth <= 1.3
		});

		if (cDimI < 0 || vDimsI.length < 4) {
			return;
		}

		return {
			progress: seriesModel.pipelineContext.large ? largeProgress : normalProgress
		};

		function normalProgress(params, data) {
			var dataIndex;
			var store = data.getStore();

			while ((dataIndex = params.next()) != null) {
				var axisDimVal = store.get(cDimI, dataIndex);
				var openVal = store.get(openDimI, dataIndex);
				var closeVal = store.get(closeDimI, dataIndex);
				var lowestVal = store.get(lowestDimI, dataIndex);
				var highestVal = store.get(highestDimI, dataIndex);
				var ocLow = Math.min(openVal, closeVal);
				var ocHigh = Math.max(openVal, closeVal);
				var ocLowPoint = getPoint(ocLow, axisDimVal);
				var ocHighPoint = getPoint(ocHigh, axisDimVal);
				var lowestPoint = getPoint(lowestVal, axisDimVal);
				var highestPoint = getPoint(highestVal, axisDimVal);
				var ends = [];
				addBodyEnd(ends, ocHighPoint, 0);
				addBodyEnd(ends, ocLowPoint, 1);
				ends.push(subPixelOptimizePoint(highestPoint), subPixelOptimizePoint(ocHighPoint), subPixelOptimizePoint(lowestPoint), subPixelOptimizePoint(ocLowPoint));
				var itemModel = data.getItemModel(dataIndex);
				var hasDojiColor = !!itemModel.get(['itemStyle', 'borderColorDoji']);
				data.setItemLayout(dataIndex, {
					sign: getSign(store, dataIndex, openVal, closeVal, closeDimI, hasDojiColor),
					initBaseline: openVal > closeVal ? ocHighPoint[vDimIdx] : ocLowPoint[vDimIdx],
					ends: ends,
					brushRect: makeBrushRect(lowestVal, highestVal, axisDimVal)
				});
			}

			function getPoint(val, axisDimVal) {
				var p = [];
				p[cDimIdx] = axisDimVal;
				p[vDimIdx] = val;
				return isNaN(axisDimVal) || isNaN(val) ? [NaN, NaN] : coordSys.dataToPoint(p);
			}

			function addBodyEnd(ends, point, start) {
				var point1 = point.slice();
				var point2 = point.slice();
				point1[cDimIdx] = subPixelOptimize(point1[cDimIdx] + candleWidth / 2, 1, false);
				point2[cDimIdx] = subPixelOptimize(point2[cDimIdx] - candleWidth / 2, 1, true);
				start ? ends.push(point1, point2) : ends.push(point2, point1);
			}

			function makeBrushRect(lowestVal, highestVal, axisDimVal) {
				var pmin = getPoint(lowestVal, axisDimVal);
				var pmax = getPoint(highestVal, axisDimVal);
				pmin[cDimIdx] -= candleWidth / 2;
				pmax[cDimIdx] -= candleWidth / 2;
				return {
					x: pmin[0],
					y: pmin[1],
					width: vDimIdx ? candleWidth : pmax[0] - pmin[0],
					height: vDimIdx ? pmax[1] - pmin[1] : candleWidth
				};
			}

			function subPixelOptimizePoint(point) {
				point[cDimIdx] = subPixelOptimize(point[cDimIdx], 1);
				return point;
			}
		}

		function largeProgress(params, data) {
			// Structure: [sign, x, yhigh, ylow, sign, x, yhigh, ylow, ...]
			var points = createFloat32Array(params.count * 4);
			var offset = 0;
			var point;
			var tmpIn = [];
			var tmpOut = [];
			var dataIndex;
			var store = data.getStore();
			var hasDojiColor = !!seriesModel.get(['itemStyle', 'borderColorDoji']);

			while ((dataIndex = params.next()) != null) {
				var axisDimVal = store.get(cDimI, dataIndex);
				var openVal = store.get(openDimI, dataIndex);
				var closeVal = store.get(closeDimI, dataIndex);
				var lowestVal = store.get(lowestDimI, dataIndex);
				var highestVal = store.get(highestDimI, dataIndex);

				if (isNaN(axisDimVal) || isNaN(lowestVal) || isNaN(highestVal)) {
					points[offset++] = NaN;
					offset += 3;
					continue;
				}

				points[offset++] = getSign(store, dataIndex, openVal, closeVal, closeDimI, hasDojiColor);
				tmpIn[cDimIdx] = axisDimVal;
				tmpIn[vDimIdx] = lowestVal;
				point = coordSys.dataToPoint(tmpIn, null, tmpOut);
				points[offset++] = point ? point[0] : NaN;
				points[offset++] = point ? point[1] : NaN;
				tmpIn[vDimIdx] = highestVal;
				point = coordSys.dataToPoint(tmpIn, null, tmpOut);
				points[offset++] = point ? point[1] : NaN;
			}

			data.setLayout('largePoints', points);
		}
	}
};
/**
 * Get the sign of a single data.
 *
 * @returns 0 for doji with hasDojiColor: true,
 *          1 for positive,
 *          -1 for negative.
 */

function getSign(store, dataIndex, openVal, closeVal, closeDimI, hasDojiColor) {
	var sign;

	if (openVal > closeVal) {
		sign = -1;
	} else if (openVal < closeVal) {
		sign = 1;
	} else {
		sign = hasDojiColor // When doji color is set, use it instead of color/color0.
			? 0 : dataIndex > 0 // If close === open, compare with close of last record
				? store.get(closeDimI, dataIndex - 1) <= closeVal ? 1 : -1 : // No record of previous, set to be positive
				1;
	}

	return sign;
}

function calculateCandleWidth(seriesModel, data) {
	var baseAxis = seriesModel.getBaseAxis();
	var extent;
	var bandWidth = baseAxis.type === 'category' ? baseAxis.getBandWidth() : (extent = baseAxis.getExtent(), Math.abs(extent[1] - extent[0]) / data.count());
	var barMaxWidth = parsePercent(retrieve2(seriesModel.get('barMaxWidth'), bandWidth), bandWidth);
	var barMinWidth = parsePercent(retrieve2(seriesModel.get('barMinWidth'), 1), bandWidth);
	var barWidth = seriesModel.get('barWidth');
	return barWidth != null ? parsePercent(barWidth, bandWidth) // Put max outer to ensure bar visible in spite of overlap.
		: Math.max(Math.min(bandWidth / 2, barMaxWidth), barMinWidth);
}

export default candlestickLayout;